package com.aliang.shopping.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.aliang.shopping.common.PageResult;
import com.aliang.shopping.common.Result;
import com.aliang.shopping.common.ResultCodeEnum;
import com.aliang.shopping.config.OssConfig;
import com.aliang.shopping.contact.ResultMsgContact;
import com.aliang.shopping.contact.SqlColumnConstant;
import com.aliang.shopping.exception.DataException;
import com.aliang.shopping.exception.ServiceException;
import com.aliang.shopping.log.annotation.OperateLog;
import com.aliang.shopping.log.enums.OperateType;
import com.aliang.shopping.model.converter.GoodsConverter;
import com.aliang.shopping.model.dto.common.UpdateStatusDTO;
import com.aliang.shopping.model.dto.goods.*;
import com.aliang.shopping.model.enums.UserTypeEnum;
import com.aliang.shopping.model.po.Goods;
import com.aliang.shopping.model.po.GoodsProperties;
import com.aliang.shopping.model.po.GoodsSku;
import com.aliang.shopping.model.vo.CommonUserInfoVO;
import com.aliang.shopping.model.vo.goods.GoodsVO;
import com.aliang.shopping.security.Auth;
import com.aliang.shopping.security.PreventRepeatSubmit;
import com.aliang.shopping.security.auth.Payload;
import com.aliang.shopping.security.auth.UserHolder;
import com.aliang.shopping.service.GoodsPropertiesService;
import com.aliang.shopping.service.GoodsService;
import com.aliang.shopping.service.GoodsSkuService;
import com.aliang.shopping.service.OrdersInfoService;
import com.aliang.shopping.util.SearchHostUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/goods")
@AllArgsConstructor
public class GoodsController {

    private final GoodsService goodsService;
    private final GoodsConverter goodsConverter;
    private final GoodsPropertiesService goodsPropertiesService;
    private final GoodsSkuService goodsSkuService;
    private final OssConfig ossConfig;
    private final OrdersInfoService ordersInfoService;

    /**
     * 商品信息插入
     *
     * @param insertDTO
     * @return
     */
    @PostMapping("/insert")
    @ApiOperation("商品信息插入")
    @PreventRepeatSubmit
    @OperateLog(title = "商品信息插入", type = OperateType.INSERT)
    @Auth(role = UserTypeEnum.BUSINESS)
    @Transactional
    public Result<String> insertGoods(@RequestBody GoodsInsertDTO insertDTO) {
        //数据不能为空
        if (BeanUtil.hasNullField(insertDTO)
                || StrUtil.hasBlank(insertDTO.getGoodsName())
                || insertDTO.getTypeId().isEmpty()
                || insertDTO.getMainImages().isEmpty()
                || insertDTO.getImageDesc().isEmpty()
        ) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //截取图片路径
        insertDTO.setMainImages(insertDTO.getMainImages().stream()
                .map(item -> StrUtil.subAfter(item, ossConfig.getUrl(), false))
                .collect(Collectors.toList()));
        insertDTO.setImageDesc(insertDTO.getImageDesc().stream()
                .map(item -> StrUtil.subAfter(item, ossConfig.getUrl(), false))
                .collect(Collectors.toList()));
        //数据转化
        Goods poByInsertDTO = this.goodsConverter.toPoByInsertDTO(insertDTO);
        //设置商家id
        Long userId = UserHolder.getUserId();
        poByInsertDTO.setBusinessId(userId);


        // 保存数据
        boolean save = this.goodsService.save(poByInsertDTO);
        if (!save) {
            return Result.fail(ResultMsgContact.INSERT_FAIL);
        }
        //插入配置信息
        List<GoodsProperties> propertiesPoByList = insertDTO.getProperties().stream()
                .map((item) -> this.goodsConverter.getPropertiesPo(item, poByInsertDTO.getId()))
                .collect(Collectors.toList());
        boolean saveBatch = this.goodsPropertiesService.saveBatch(propertiesPoByList);
        if (!saveBatch) {
            return Result.fail(ResultMsgContact.INSERT_FAIL);
        }
        return Result.ok(ResultMsgContact.INSERT_SUCCESS);
    }

    /**
     * 商品信息删除
     *
     * @param ids
     * @return
     */
    @DeleteMapping("/del")
    @ApiOperation("商品信息删除")
    @PreventRepeatSubmit
    @OperateLog(title = "商品信息删除", type = OperateType.DELETE)
    @Transactional
    public Result<String> delGoods(@RequestBody List<Long> ids) {
        //判断是否有sku信息
        int count = this.goodsSkuService.count(
                new LambdaQueryWrapper<GoodsSku>()
                        .in(GoodsSku::getGoodsId, ids)
        );
        //如果有不能删除
        if (count > 0)
            throw new DataException(ResultCodeEnum.HAS_GOODS_SKU_BY_DEL);
        //根据删除Id删除配置信息
        boolean remove = this.goodsPropertiesService.remove(new LambdaQueryWrapper<GoodsProperties>()
                .in(GoodsProperties::getGoodsId, ids));
        if (!remove) {
            return Result.fail(ResultMsgContact.DELETE_FAIL);
        }
        //删除数据库信息
        boolean removeByIds = this.goodsService.removeByIds(ids);
        if (!removeByIds) {
            return Result.fail(ResultMsgContact.DELETE_FAIL);
        }
        // 删除Es的信息
        this.goodsService.deleteByEs(ids);
        return Result.ok(ResultMsgContact.DELETE_SUCCESS);
    }

    /**
     * 商品信息更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update")
    @ApiOperation("商品信息更改")
    @PreventRepeatSubmit
    @OperateLog(title = "商品信息更改", type = OperateType.UPDATE)
    @Auth(role = UserTypeEnum.BUSINESS)
    @Transactional
    public Result<String> updateGoods(@RequestBody GoodsUpdateDTO updateDTO) {
        //数据不能为空
        if (BeanUtil.hasNullField(updateDTO)
                || StrUtil.hasBlank(updateDTO.getGoodsName())
                || updateDTO.getMainImages().isEmpty()
                || updateDTO.getImageDesc().isEmpty()
        ) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //截取图片路径
        updateDTO.setMainImages(updateDTO.getMainImages().stream()
                .map(item -> StrUtil.subAfter(item, ossConfig.getUrl(), false))
                .collect(Collectors.toList()));
        updateDTO.setImageDesc(updateDTO.getImageDesc().stream()
                .map(item -> StrUtil.subAfter(item, ossConfig.getUrl(), false))
                .collect(Collectors.toList()));
        //转换数据
        Goods goods = this.goodsConverter.toPoByUpdateDTO(updateDTO);
        //保存数据
        this.goodsService.updateById(goods);
        //保存在es中
        this.goodsService.updateGoodsToEs(goods);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 商品配置信息更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update_properties/{goodsId}")
    @ApiOperation("商品配置信息更改")
    @PreventRepeatSubmit
    @OperateLog(title = "商品配置信息更改", type = OperateType.UPDATE)
    @Auth(role = UserTypeEnum.BUSINESS)
    @Transactional
    public Result<String> updateGoodsProperties(@PathVariable("goodsId") Long goodsId, @RequestBody List<GoodsPropertiesInsert> updateDTO) {
        //数据不能为空
        if (updateDTO.isEmpty()) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //删除原本的配置信息
        this.goodsPropertiesService.remove(new LambdaQueryWrapper<GoodsProperties>()
                .eq(GoodsProperties::getGoodsId, goodsId));
        //转换数据
        List<GoodsProperties> propertiesPoByList = updateDTO.stream()
                .map((item) -> this.goodsConverter.getPropertiesPo(item, goodsId))
                .collect(Collectors.toList());
        //插入配置信息
        this.goodsPropertiesService.saveBatch(propertiesPoByList);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }


    /**
     * 商品信息状态更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update_static")
    @ApiOperation("商品信息状态更改")
    @PreventRepeatSubmit
    @OperateLog(title = "商品信息状态更改", type = OperateType.UPDATE_STATUS)
    @Auth(role = UserTypeEnum.BUSINESS)
    public Result<String> updateGoodsStatic(@RequestBody UpdateStatusDTO updateDTO) {
        //必要字段非空校验
        if (BeanUtil.isEmpty(updateDTO)
        ) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }

        //如果状态为1，即上架，需要有sku信息,并且在售卖
        if (updateDTO.getStatus() == 1) {
            LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<GoodsSku>()
                    .eq(GoodsSku::getGoodsId, updateDTO.getId())
                    .eq(GoodsSku::getIsSell, SqlColumnConstant.STATUS_OK);
            int count = this.goodsSkuService.count(queryWrapper);
            // 没有sku信息，抛出异常
            if (count <= 0) {
                throw new DataException(ResultCodeEnum.GOODS_SKU_IS_NOT_SELL);
            }
            // 更新es数据
            this.goodsService.updateStatusToEs(updateDTO.getId());
        } else {
            //下架，删除es数据
            this.goodsService.deleteByEs(Collections.singletonList(updateDTO.getId()));
        }
        //转换数据
        Goods goods = this.goodsConverter.toPoByUpdateStaticDTO(updateDTO);
        //更新数据
        this.goodsService.updateById(goods);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 商品信息分页搜索
     */
    @GetMapping("/getPage")
    @ApiOperation("商品信息分页搜索")
    public Result<PageResult<GoodsVO>> queryGoodsPage(GoodsPageDto pageDTO) {
        //必要字段校验
        if (ObjectUtil.hasNull(pageDTO.getPageSize(), pageDTO.getPageNum())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //获取ID。只允许商家查询自己的商品
        Payload payload = UserHolder.get();
        if (Objects.equals(payload.getRole(), UserTypeEnum.BUSINESS.getCode())) {
            //设置商家Id
            pageDTO.setBusinessId(payload.getId());
        }
        //查询数据
        PageResult<GoodsVO> result = this.goodsService.selectPage(pageDTO);
        return Result.ok(result);
    }


    /**
     * ES商品信息分页搜索
     */
    @GetMapping("/getListWithEs")
    @ApiOperation("ES商品信息分页搜索")
    public Result<List<GoodsEsDto>> getListWithEs(GoodsPageDto goodsPageDto) {
        //必要字段校验
        if (ObjectUtil.hasNull(goodsPageDto.getPageSize(), goodsPageDto.getPageNum())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //查询数据
        List<GoodsEsDto> result = this.goodsService.getListPageWithEs(goodsPageDto);
        return Result.ok(result);
    }


    @GetMapping("/getGoodsInfoById/{goodsId}")
    @ApiOperation("根据商品Id获取商品信息")
    public Result<GoodsVO> getGoodsInfoById(@PathVariable Long goodsId) {
        Goods byId = this.goodsService.getById(goodsId);
        if (Objects.isNull(byId)) {
            throw new ServiceException(ResultCodeEnum.GOODS_IS_NOT_EXIT);
        }
        GoodsVO vo = this.goodsConverter.toVo(byId);
        //主图不为空，设置完整路径
        if (!vo.getMainImages().isEmpty()) {
            vo.setMainImages(vo.getMainImages().stream().map(item -> ossConfig.getUrl() + item).collect(Collectors.toList()));
        }
        //图文描述不为空，设置完整路径
        if (!vo.getImageDesc().isEmpty()) {
            vo.setImageDesc(vo.getImageDesc().stream().map(item -> ossConfig.getUrl() + item).collect(Collectors.toList()));
        }
        //查询规格信息
        List<GoodsProperties> list = this.goodsPropertiesService.list(new LambdaQueryWrapper<GoodsProperties>()
                .eq(GoodsProperties::getGoodsId, goodsId));
        //设置规格信息
        if (!list.isEmpty())
            vo.setProperties(this.goodsConverter.getPropertiesVoList(list));
        // 获取销售数量
        Map<Long, Integer> saleNumByGoodsId = this.ordersInfoService.getSaleNumByGoodsId(Collections.singletonList(goodsId));
        vo.setSaleNum(saleNumByGoodsId.getOrDefault(goodsId, 0));
        return Result.ok(vo);
    }

    private final SearchHostUtil searchHostUtil;

    @ApiOperation("获取热门搜索前10条")
    @GetMapping("/getHost")
    public Result<Set<Object>> getHost() {
        Set<Object> strSet = searchHostUtil.reverseRange(0, 10 - 1); //正确个数为下标-1
        return Result.ok(strSet);
    }


    @ApiOperation("根据商品Id获取商家基本信息")
    @GetMapping("/getBusinessInfoById/{goodsId}")
    public Result<CommonUserInfoVO> getBusinessInfoById(@PathVariable Long goodsId) {
        CommonUserInfoVO infoVO = this.goodsService.getBusinessInfoById(goodsId);
        return Result.ok(infoVO);
    }

    @ApiOperation("根据商品Id获取商品信息列表")
    @PostMapping("/getGoodsListById")
    public Result<List<GoodsEsDto>> getGoodsListById(@RequestBody List<Long> goodsIds) {
        List<GoodsEsDto> list = this.goodsService.getGoodsListById(goodsIds);
        return Result.ok(list);
    }

    @ApiOperation("获取用户收藏商品信息列表")
    @PostMapping("/getGoodsListByCollect")
    public Result<List<GoodsEsDto>> getGoodsListByCollect() {
        //获取登录用户Id
        Long userId = UserHolder.getUserId();
        List<GoodsEsDto> list = this.goodsService.getGoodsListByUserId(userId);
        return Result.ok(list);
    }

    @ApiOperation("获取商品推荐列表")
    @PostMapping("/getRecommendGoodsList")
    public Result<List<GoodsEsDto>> getRecommendGoodsList() {
        //获取登录用户Id
        Long userId = Objects.nonNull(UserHolder.get()) ? UserHolder.getUserId() : null;
        List<GoodsEsDto> list = this.goodsService.getRecommendGoodsList(userId);
        return Result.ok(list);
    }

    @ApiOperation("获取首页其他标签列表")
    @GetMapping("/getOrderList")
    public Result<List<GoodsEsDto>> getOrderList(String keyword) {
        List<GoodsEsDto> list = this.goodsService.getOrderList(keyword);
        return Result.ok(list);
    }
}
